package com.example.demo.utils;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * json工具类
 */
public class JsonUtils {
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 创建基本gson
     *
     * @param names
     * @return gson对象
     */
    public static Gson createGson(final String... names) {
        ExclusionStrategy exclusionStrategy = new ExclusionStrategy() {

            @Override
            public boolean shouldSkipField(FieldAttributes fa) {
                if (isEmpty(names)) {
                    return false;
                }
                for (String name : names) {
                    if (fa.getName().equals(name)) {
                        return true;
                    }
                }
                return false;
            }

            @Override
            public boolean shouldSkipClass(Class<?> arg0) {
                return false;
            }
        };

        return build(DEFAULT_DATE_PATTERN, exclusionStrategy).create();
    }

    /**
     * 将json数据转化成map对象
     *
     * @param json json字符串
     * @return Map<String, String>
     */
    public static Map<String, String> toMap(String json) {
        return createGson().fromJson(json, new TypeToken<Map<String, String>>() {
        }.getType());
    }

    /**
     * 将对象转换成json字符串
     *
     * @param object
     * @return
     */
    public static String toJson(Object object) {
        return createGson().toJson(object);
    }

    /**
     * 将对象转换成json格式map
     *
     * @param object
     * @return
     */
    public static Map<String, String> toJsonMap(Object object) {
        return toMap(toJson(object));
    }

    /**
     * 格式化字段名成json数据 <br>
     * someFieldName ---> some_field_name
     *
     * @param object
     * @return
     */
    public static String formatFiledName(Object object) {
        return build(true).create().toJson(object);
    }

    /**
     * 格式化字段名并转换成对象<br>
     * someFieldName ---> some_field_name
     *
     * @param <T>
     * @param json
     * @return
     */
    public static <T> T parseFiledName(String json, Class<T> clazz) {
        T newInstance = null;
        try {
            newInstance = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            return null;
        }
        Gson gson = build(true).create();
        if (newInstance instanceof Collection || newInstance instanceof Map) {
            return gson.fromJson(json, new TypeToken<T>() {
            }.getType());
        }
        T t = gson.fromJson(json, clazz);
        if (t == null) {
            return null;
        }
        return t;
    }

    /**
     * 转换成对象
     *
     * @param <T>
     * @param json
     * @return
     */
    public static <T> T parse(String json, Class<T> clazz) {
        T newInstance = null;
        try {
            newInstance = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            return null;
        }
        Gson gson = build(false).create();
        if (newInstance instanceof Collection || newInstance instanceof Map) {
            return gson.fromJson(json, new TypeToken<T>() {
            }.getType());
        }
        T t = gson.fromJson(json, clazz);
        if (t == null) {
            return null;
        }
        return t;
    }

    /**
     * 格式化Map字段名并转换成对象<br>
     * some_field_name ---> someFieldName
     *
     * @param map
     * @param clazz
     * @return
     * @throws Exception
     */
    public static <T, K, V> T parseFiledName(Map<K, V> map, Class<T> clazz) throws Exception {
        return parseFiledName(toJson(map), clazz);
    }

    /**
     * 将JSON转成List对象
     */
    public static <T> List<T> toList(String json, Class<T[]> clazz) {
        T[] array = createGson().fromJson(json, clazz);
        return Arrays.asList(array);
    }

    /**
     * 将对象的字段名格式化并转换成map
     *
     * @param object
     * @return
     */
    public static Map<String, String> formatFiledtoMap(Object object) {
        return toMap(formatFiledName(object));
    }

    private static GsonBuilder build(boolean isFormat) {
        return build(isFormat, DEFAULT_DATE_PATTERN);
    }

    public static GsonBuilder build(String dateFormat, ExclusionStrategy... exclusionStrategy) {
        return build(false, dateFormat, exclusionStrategy);
    }

    public static GsonBuilder build(boolean isFormat, String dateFormat, ExclusionStrategy... exclusionStrategy) {
        return build(isFormat, true, dateFormat, exclusionStrategy);
    }

    private static GsonBuilder build(boolean isFormat, boolean isLongToString, String dateFormat,
        ExclusionStrategy... exclusionStrategy) {
        GsonBuilder gsonBuilder = new GsonBuilder();
        if (isFormat) {
            gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
        }
        if (isLongToString) {
            gsonBuilder.setLongSerializationPolicy(LongSerializationPolicy.STRING);
        }
        if (isNotBlank(dateFormat)) {
            gsonBuilder.setDateFormat(dateFormat);
        }
        if (exclusionStrategy != null) {
            gsonBuilder.setExclusionStrategies(exclusionStrategy);
        }
        return gsonBuilder;
    }

    public static boolean isEmpty(Object[] array) {
        return getLength(array) == 0;
    }

    public static int getLength(Object array) {
        return array == null ? 0 : Array.getLength(array);
    }

    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs != null && (strLen = cs.length()) != 0) {
            for(int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }
}
